package com.logistica.metropolitana.web.controllers;


import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.io.IOUtils;
import org.imgscalr.Scalr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.logistica.metropolitana.common.web.BaseController;
import com.logistica.metropolitana.exceptions.ActaDeEntregaException;
import com.logistica.metropolitana.services.ActaDeEntregaService;
import com.logistica.metropolitana.web.views.AEImagenView;
import com.logistica.metropolitana.web.views.ActaDeEntregaView;
import com.logistica.metropolitana.web.views.VisitaView;
/**
 *
 * @author rioslore
 *
 */
@Controller
public class ActaDeEntregaController extends BaseController{

	private final Logger logger = LoggerFactory.getLogger(ActaDeEntregaController.class);

	private static final int IMG_WIDTH = 1600;
	private static final int IMG_HEIGHT = 1200;

	@Autowired
	ActaDeEntregaService actaDeEntregaService;
	@Autowired(required=false)
	ServletContext servletContext;

	@RequestMapping(value = "ajax/actas_de_entrega", method = RequestMethod.GET)
	public String goActasList(Model model, HttpServletRequest request, HttpSession session) throws ActaDeEntregaException {
		try{
			logger.info("Dentro Acta de Entrega Listado");
			model.addAttribute("actas", actaDeEntregaService.getActasDeEntrega());
		}catch(ActaDeEntregaException aEntregaException){
			session.setAttribute(CUSTOM_EXCEPTION, aEntregaException);
			throw aEntregaException;
		}catch(Exception e){
			logger.error("Ocurrió un error al obtener la lista de Actas de Entrega {}", e);
			ActaDeEntregaException sException = new ActaDeEntregaException(e,
					ActaDeEntregaException.LAYER_CONTROLLER, ActaDeEntregaException.ACTION_SELECT);
			session.setAttribute(CUSTOM_EXCEPTION, sException);
			throw sException;
		}

		return "actas_de_entrega";
	}

	@SuppressWarnings({ "deprecation", "unchecked" })
	@RequestMapping(value="actas/{posicion}/upload", method = RequestMethod.POST)
	public @ResponseBody String upload(@RequestParam("file") MultipartFile file,
			@PathVariable("posicion") Integer posicion, HttpServletResponse response, HttpSession session) {
		Map<Integer, AEImagenView> imagenes = Maps.newLinkedHashMap();
		imagenes = (Map<Integer, AEImagenView>) session.getAttribute("imagenesMap");
		logger.info("File name {}",file.getOriginalFilename());
		Long rn = (long) (Math.random()*1000000000);
		Long randomName = System.currentTimeMillis();
		try {
			String type = file.getContentType();
			if(type.toLowerCase().contains("image")){
				AEImagenView view = resizeImagen(file, posicion);
				imagenes.remove(posicion);
				imagenes.put(posicion, view);
				session.setAttribute("imagenesMap", imagenes);
				return "<img src='rest/actas/"+posicion+"/mostrarimagen/"+randomName+""+rn+"' alt='Sin Imagen' onError='this.onerror=null;this.src='';' />";
			}	
		} catch (IOException e) {
			String msg = "Ocurrió un error al tratar de guardar la imagen";
			logger.error(msg, e);
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
		}

		return "<img src='' alt='Sin Imagen' onError='this.onerror=null;this.src='';'/>";
	}

	@RequestMapping(value="validar/{gidActa}/acta", method = RequestMethod.GET)
	public @ResponseBody Boolean verifyGid(@PathVariable("gidActa") String gid,
			HttpServletResponse response) {
		logger.info("Validar gid: "+gid);
		Boolean respuesta = false;
		try{
			respuesta = actaDeEntregaService.validarGidActa(gid);
		} catch(ActaDeEntregaException aException){
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
		} catch (Exception e) {
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
		}
		return respuesta;
	}

	@RequestMapping(value = "ajax/buscar_acta_de_entrega", method = RequestMethod.GET)
	public String goSearchActa(Model model,HttpSession session) throws ActaDeEntregaException {
		session.removeAttribute("imagenesMap");
		return "buscar_acta_de_entrega";
	}

	@RequestMapping(value = "ajax/{gidActa}/buscar_acta_de_entrega", method = RequestMethod.GET)
	public String searchActa(@PathVariable("gidActa") String gid, Model model, HttpServletRequest request, HttpSession session) throws ActaDeEntregaException {
		logger.info("Buscar Acta: "+gid);
		try{
			List<ActaDeEntregaView> actas = null;
			actas = actaDeEntregaService.buscaActaGID(gid);
			if(actas!=null){
				session.setAttribute(SUCCESS_MESSAGE, "Acta encontrada");
			}
			else{
				session.setAttribute(CUSTOM_EXCEPTION, "La Acta con el GID: "+gid+", no se encontro");
			}
			model.addAttribute("actas",actas);
		}catch(ActaDeEntregaException aEntregaException){
			session.setAttribute(CUSTOM_EXCEPTION, aEntregaException);
			throw aEntregaException;
		}catch(Exception e){
			logger.error("Ocurrió un error al obtener el Acta de Entrega {}", e);
			ActaDeEntregaException sException = new ActaDeEntregaException(e, 
					ActaDeEntregaException.LAYER_CONTROLLER, ActaDeEntregaException.ACTION_SELECT);
			session.setAttribute(CUSTOM_EXCEPTION, sException);
			throw sException;
		}
		return "buscar_acta_de_entrega";
	}

	@SuppressWarnings({ "deprecation", "unchecked" })
	@RequestMapping(value = "actas/{posicion}/mostrarimagen/{value}", method = RequestMethod.GET)
	public void get(@PathVariable("posicion") Integer seccion, @PathVariable("value") String value, HttpServletResponse response, HttpSession session){
 		try {
 			Map<Integer, AEImagenView> imagenes = (Map<Integer, AEImagenView>) session.getAttribute("imagenesMap");
 			for(Integer count = 1;count<27 ;count++){
 				AEImagenView view = imagenes.get(count);
 				if(view!=null){
 					if(view.getPosicion()==seccion){
 						response.setContentType(view.getType());
 						response.setContentLength(view.getLength());
 						FileCopyUtils.copy(view.getBytes(), response.getOutputStream());
 						break;
 					}

 				}
 			}
		} catch (IOException e) {
			String msg = "Ocurrió un error al tratar de mostrar la imagen";
			logger.error(msg, e);
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
		}
	}

	@RequestMapping(value = "ajax/agregar_acta_de_entrega", method = RequestMethod.GET)
	public String goAddActa(Model model, HttpSession session) throws ActaDeEntregaException {
		logger.info("Dentro Agregar Acta de Entrega GET");
		Map<Integer, AEImagenView> imagenes = Maps.newLinkedHashMap();
		imagenes.put(new Integer(3), setDiagramaDeRed());
		session.setAttribute("imagenesMap", imagenes);
		
		model.addAttribute("actaDeEntregaView", new ActaDeEntregaView());
		return "agregar_acta_de_entrega";
	}

	@SuppressWarnings("unchecked")
	@RequestMapping(value = "ajax/agregar_acta_de_entrega", method = RequestMethod.POST)
	public @ResponseBody String addActa(
			@ModelAttribute("actaDeEntregaView") ActaDeEntregaView actaDeEntregaView,
			HttpSession httpSession, Model modelMap, HttpServletRequest request, HttpServletResponse response) {
		String result = "";
		try {
			logger.info("Dentro Agregar Acta de Entrega POST");
			logger.info("Acta de Entrega", actaDeEntregaView);
			
			String gid = actaDeEntregaView.getGid();
			if(actaDeEntregaService.existeActaDeEntrega(gid)){
				throw new ActaDeEntregaException("El GID " + gid + " ya existe" ,
						ActaDeEntregaException.LAYER_SERVICE, ActaDeEntregaException.ACTION_SELECT);
			}
			Map<Integer, AEImagenView> imagenesMap = Maps.newLinkedHashMap();
			imagenesMap = (Map<Integer, AEImagenView>) httpSession.getAttribute("imagenesMap");
			List<AEImagenView> imagenes = Lists.newArrayList();
			for (Map.Entry<Integer, AEImagenView> entry : imagenesMap.entrySet()) {
				imagenes.add(entry.getValue());
			}
			httpSession.removeAttribute("imagenesMap");
			actaDeEntregaView.setImagenes(imagenes);
			actaDeEntregaService.addActaDeEntrega(actaDeEntregaView);
			result = "El acta de entrega se ha creado correctamente con id: "+actaDeEntregaView.getGid();
			httpSession.setAttribute(SUCCESS_MESSAGE, result);
			response.setStatus(HttpServletResponse.SC_OK);
		} catch(ActaDeEntregaException aException){
			result = aException.getMessage() + " - " + aException.getExceptionCode();
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
		} catch (Exception e) {
			result = "Ha ocurrido un error al tratar de procesar el formulario";
			logger.error(result);
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
		}
		return result;
	}

	@RequestMapping(value = "ajax/{gid}/editar_acta_de_entrega", method = RequestMethod.GET)
	public String goEditActa(@PathVariable("gid") String gid, Model model,
			HttpSession httpSession) throws ActaDeEntregaException {
		logger.info("Dentro Editar Acta de Entrega GET: "+gid);
		httpSession.removeAttribute(SUCCESS_MESSAGE);
		httpSession.removeAttribute(CUSTOM_EXCEPTION);
		try{
			httpSession.removeAttribute("imagenesMap");
			Map<Integer, AEImagenView> imagenesMap = Maps.newLinkedHashMap();
			ActaDeEntregaView actaDeEntregaView = actaDeEntregaService.getActaDeEntregaByGID(gid);
			List<AEImagenView> imagenes = actaDeEntregaView.getImagenes();
			for (AEImagenView view : imagenes) {
				imagenesMap.put(new Integer(view.getPosicion()), view);
			}
			if(imagenesMap.get(3) == null){
				imagenesMap.put(new Integer(3),setDiagramaDeRed());
			}
			httpSession.setAttribute("imagenesMap", imagenesMap);
			model.addAttribute("actaDeEntregaView", actaDeEntregaView);
		}catch(ActaDeEntregaException aException){
			httpSession.setAttribute(CUSTOM_EXCEPTION, aException);
			throw aException;
		}catch(Exception e){
			ActaDeEntregaException cException = new ActaDeEntregaException(e,
					ActaDeEntregaException.LAYER_CONTROLLER, ActaDeEntregaException.ACTION_SELECT);
			logger.error("Ha ocurrido un error al tratar de obtener el Acta de Entrega por GID {}", e);
			httpSession.setAttribute(CUSTOM_EXCEPTION, cException);
		}
		return "editar_acta_de_entrega";
	}

	@SuppressWarnings("unchecked")
	@RequestMapping(value = "ajax/editar_acta_de_entrega", method = RequestMethod.POST)
	public @ResponseBody String editarActa(@ModelAttribute("actaDeEntregaView") ActaDeEntregaView actaDeEntregaView,
			HttpSession httpSession, Model modelMap, HttpServletRequest request, HttpServletResponse response) {
		String result = "";
		try {
			Map<Integer, AEImagenView> imagenesMap = Maps.newLinkedHashMap();
			imagenesMap = (Map<Integer, AEImagenView>) httpSession.getAttribute("imagenesMap");
			logger.info("Dentro Editar Acta de Entrega POST: "+actaDeEntregaView.getGid());
			List<AEImagenView> imagenes = Lists.newArrayList();
			for (Map.Entry<Integer, AEImagenView> entry : imagenesMap.entrySet()) {
				imagenes.add(entry.getValue());
			}
			actaDeEntregaView.setImagenes(imagenes);
			httpSession.removeAttribute("imagenesMap");
			actaDeEntregaService.editActaDeEntrega(actaDeEntregaView);
			httpSession.setAttribute(SUCCESS_MESSAGE, "El acta de entrega "+actaDeEntregaView.getGid()+" se ha editado correctamente");
			response.setStatus(HttpServletResponse.SC_OK);
		} catch (Exception e) {
			ActaDeEntregaException cException = null;
			if(e instanceof ActaDeEntregaException){
				cException = (ActaDeEntregaException)e;
			}
			if(cException == null){
				cException = new ActaDeEntregaException(e,
						ActaDeEntregaException.LAYER_CONTROLLER, ActaDeEntregaException.ACTION_INSERT);
			}
			result = "Ha ocurrido un error al tratar de editar el Acta de Entrega "
						+ actaDeEntregaView.getGid()+ " - " + cException.getExceptionCode();
			logger.error(result);
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
		}
		return result;
	}

	@RequestMapping(value = "ajax/eliminar_acta_de_entrega", method = RequestMethod.GET)
	public String deleteActa(@RequestParam("gid") String gid, HttpSession httpSession) throws ActaDeEntregaException {
		try {
			actaDeEntregaService.deleteActaDeEntregaByGID(gid);
			httpSession.setAttribute(SUCCESS_MESSAGE, "El acta de entrega " + gid + " se ha eliminado correctamente");
		} catch (ActaDeEntregaException aException) {
			httpSession.setAttribute(CUSTOM_EXCEPTION, aException);
			throw aException;
		} catch(Exception e){
			ActaDeEntregaException cException = new ActaDeEntregaException(e,
					ActaDeEntregaException.LAYER_CONTROLLER, ActaDeEntregaException.ACTION_DELETE);
			logger.error("Ha ocurrido un error al tratar de eliminar la Acta de Entrega {}", e);
			httpSession.setAttribute(CUSTOM_EXCEPTION, cException);
			throw cException;
		}
		return "redirect:/home.html#ajax/actas_de_entrega.html";
	}

	@RequestMapping(value = "actas/descargarReportePDF", method = RequestMethod.GET)
	public void downloadPDF(@RequestParam("gid") String gid, HttpSession httpSession,
			HttpServletResponse response) throws ActaDeEntregaException{
		try {
			OutputStream os = response.getOutputStream();
			byte[] reportePDF = actaDeEntregaService.generarReporteById(servletContext, gid);
			os.write(reportePDF);
			response.setContentType("application/pdf");
		} catch (ActaDeEntregaException aException) {
			httpSession.setAttribute(CUSTOM_EXCEPTION, aException);
			throw aException;
		} catch (IOException e) {
			ActaDeEntregaException cException = new ActaDeEntregaException(e,
					ActaDeEntregaException.LAYER_CONTROLLER, ActaDeEntregaException.ACTION_SELECT);
			logger.error("Ha ocurrido un error al tratar de generar el Reporte {}", e);
			httpSession.setAttribute(CUSTOM_EXCEPTION, cException);
			throw cException;
		}
	}

	@RequestMapping(value = "ajax/{gid}/visitas_acta_de_entrega", method = RequestMethod.GET)
	public String goVisita(@PathVariable("gid") String gid, Model model,
			HttpSession httpSession) throws ActaDeEntregaException {
		try{
			logger.info("Dentro de mostrar Actas");
			model.addAttribute("visitas", actaDeEntregaService.getActaDeEntregaVisitasByGID(gid));
			model.addAttribute("idActa",gid);
		}catch(ActaDeEntregaException aException){
			httpSession.setAttribute(CUSTOM_EXCEPTION, aException);
			throw aException;
		}catch(Exception e){
			ActaDeEntregaException cException = new ActaDeEntregaException(e,
					ActaDeEntregaException.LAYER_CONTROLLER, ActaDeEntregaException.ACTION_SELECT);
			logger.error("Ha ocurrido un error al tratar de obtener el Acta de Entrega por GID {}", e);
			httpSession.setAttribute(CUSTOM_EXCEPTION, cException);
		}
		return "visitas_acta_de_entrega";
	}

	@RequestMapping(value = "ajax/{idActa}/agregar_visita_acta", method = RequestMethod.GET)
	public String goAddVisitaActa(@PathVariable("idActa") String gid, Model model,
			HttpSession httpSession) throws ActaDeEntregaException {
			logger.info("Dentro Agregar Visita Acta GET");
			model.addAttribute("visitaView", new VisitaView());
			model.addAttribute("idActa", gid);
		return "agregar_visita_acta";
	}

	@RequestMapping(value = "ajax/agregar_visita_acta", method = RequestMethod.POST)
	public String addVisitaActa(@ModelAttribute("visitaView") VisitaView visitaView,
			HttpSession httpSession, Model model, HttpServletRequest request)
			throws ActaDeEntregaException {
		try{
			logger.info("Dentro de Agregar Visita POST");
			if(actaDeEntregaService.addVisita(visitaView)){
				httpSession.setAttribute(SUCCESS_MESSAGE, "La visita se ha agregado correctamente");
			}
			else{
				httpSession.setAttribute(CUSTOM_EXCEPTION, "Ya no se pueden agregar mas Visitas para esta acta");
			}
		}catch(ActaDeEntregaException aException){
			httpSession.setAttribute(CUSTOM_EXCEPTION, aException);
			throw aException;
		}catch(Exception e){
			ActaDeEntregaException cException = new ActaDeEntregaException(e,
					ActaDeEntregaException.LAYER_CONTROLLER, ActaDeEntregaException.ACTION_SELECT);
			logger.error("Ha ocurrido un error al tratar de agregar la visita al Acta", e);
			httpSession.setAttribute(CUSTOM_EXCEPTION, cException);
		}
		return "redirect:/home.html#ajax/visitas_acta_de_entrega.html";
	}

	private AEImagenView resizeImagen(MultipartFile file, Integer posicion) throws IOException {

		AEImagenView view = new AEImagenView();
		view.setName(file.getOriginalFilename());
		view.setType(file.getContentType());
		view.setPosicion(posicion);

		InputStream in = new ByteArrayInputStream(file.getBytes());
		BufferedImage originalImage = ImageIO.read(in);

		int originalWidth = originalImage.getWidth();
		int originalHeight = originalImage.getHeight();

		if((originalWidth > IMG_WIDTH) && (originalHeight > IMG_HEIGHT)){
			BufferedImage resizeImageJpg = Scalr.resize(originalImage, Scalr.Method.SPEED,
					Scalr.Mode.FIT_TO_WIDTH, IMG_WIDTH, IMG_HEIGHT, Scalr.OP_ANTIALIAS);

			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ImageIO.write(resizeImageJpg, "jpg", baos);
			baos.flush();
			byte[] imagen = baos.toByteArray();
			view.setBytes(imagen);
			view.setLength(imagen.length);
			baos.close();
		}else{
			view.setBytes(file.getBytes());
			view.setLength(file.getBytes().length);
		}
		return view;
	}
	
	private AEImagenView setDiagramaDeRed(){
		InputStream imagenInputStream = servletContext
				.getResourceAsStream("/WEB-INF/classes/reportes/img/diagrama_de_red_megacable.jpg");
		AEImagenView diagramaDeRedIMG = new AEImagenView();
		try {
			byte[] diagramaRedMegacable = IOUtils.toByteArray(imagenInputStream);
			diagramaDeRedIMG.setBytes(diagramaRedMegacable);
			diagramaDeRedIMG.setLength(diagramaRedMegacable.length);
			diagramaDeRedIMG.setName("diagrama_de_red_megacable.jpg");
			diagramaDeRedIMG.setPosicion(3);
			diagramaDeRedIMG.setType("image/jpg");
			diagramaDeRedIMG.setSeccion("Seccion 3");
		} catch (IOException e) {
			logger.error("Ha ocurrido un error al tratar de obtener la imagen del diagrama de red",e);
		}
		return diagramaDeRedIMG;
	}
}
